package falcon.script;

public final class FalconLangInstruction {

	public static final int NOP = 0;
	public static final int TEST = 1;
	public static final int MOV = 2;
	public static final int CALL = 3;
	public static final int RET = 4;
	public static final int JMP = 5;
	public static final int JE = 6;
	public static final int JNE = 7;
	public static final int JZ = 8;
	public static final int JNZ = 9;
	public static final int JG = 10;
	public static final int JGE = 11;
	public static final int JL = 12;
	public static final int JLE = 13;
	public static final int JOIN = 14;
	public static final int ADD = 15;
	public static final int SUB = 16;
	public static final int MUL = 17;
	public static final int DIV = 18;
	public static final int MOD = 19;
	
	public static final class Operand {
		public static final int LABEL = 0;
		public static final int CONST = 1;
		public static final int TMP = 2;
		public static final int VAR = 3;
		public static final int ARG = 4;
		public static final int FUNC = 5;
		public static final int FLOW = 6;
		public static final int SYS = 7;
		
		public int type;
		public String value;
		
		public Operand(int type, String value) {
			this.type = type;
			this.value = value;
		}
		
		@Override
		public String toString() {
			String info;
			if (this.type == CONST) {
				info = String.format("CONST:\"%s\"", this.value);
			} else if (this.type == TMP) {
				info = String.format("TMP[%s]", this.value);
			} else if (this.type == VAR) {
				info = String.format("VAR{%s}", this.value);
			} else if (this.type == ARG) {
				String v = this.value.startsWith("$") ? this.value.substring(1) : this.value;
				info = String.format("ARG[%s]", v);
			} else if (this.type == FUNC) {
				info = String.format("FUNC.%s", this.value);
			} else if (this.type == FLOW) {
				info = String.format("FLOW.%s", this.value);
			} else if (this.type == SYS) {
				info = String.format("SYS.%s", this.value);
			} else {// type == LABEL
				info = String.format("LABEL:%s", this.value);
			}
			return info;
		}
	}
	
	public static final class Label {
		public static final String BLOCK_BEGIN = "begin";
		public static final String BLOCK_END = "end";
	}
	
	public int code;
	public Operand operand1;
	public Operand operand2;
	
	public FalconLangInstruction(int code) {
		this.code = code;
		this.operand1 = null;
		this.operand2 = null;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(128);
		if (this.code == TEST) {
			sb.append("TEST");
		} else if (this.code == MOV) {
			sb.append("MOV");
		} else if (this.code == CALL) {
			sb.append("CALL");
		} else if (this.code == RET) {
			sb.append("RET");
		} else if (this.code == JMP) {
			sb.append("JMP");
		} else if (this.code == JE) {
			sb.append("JE");
		} else if (this.code == JNE) {
			sb.append("JNE");
		} else if (this.code == JZ) {
			sb.append("JZ");
		} else if (this.code == JNZ) {
			sb.append("JNZ");
		} else if (this.code == JG) {
			sb.append("JG");
		} else if (this.code == JGE) {
			sb.append("JGE");
		} else if (this.code == JL) {
			sb.append("JL");
		} else if (this.code == JLE) {
			sb.append("JLE");
		} else if (this.code == JOIN) {
			sb.append("JOIN");
		} else if (this.code == ADD) {
			sb.append("ADD");
		} else if (this.code == SUB) {
			sb.append("SUB");
		} else if (this.code == MUL) {
			sb.append("MUL");
		} else if (this.code == DIV) {
			sb.append("DIV");
		} else if (this.code == MOD) {
			sb.append("MOD");
		} else {// code == NOP
			sb.append("NOP");
		}
		sb.append(' ');
		if (this.operand1 != null) {
			sb.append(this.operand1.toString());
		}
		if (this.operand2 != null) {
			sb.append(", ");
			sb.append(this.operand2.toString());
		}
		return sb.toString();
	}
}
